DockerでMosquitteを立ててAWS IoTのMQTTトピックにPublishをしてみる
こんにちは、CX事業本部の若槻です。
AWS IoT上のMQTTトピックに対してDockerコンテナ上のMosquitteからメッセージをpublishする検証をしてみたのでご紹介します。
Eclipse Mosquitto is an open source (EPL/EDL licensed) message broker that implements the MQTT protocol versions 5.0, 3.1.1 and 3.1. Mosquitto is lightweight and is suitable for use on all devices from low power single board computers to full servers.
The MQTT protocol provides a lightweight method of carrying out messaging using a publish/subscribe model. This makes it suitable for Internet of Things messaging such as with low power sensors or mobile devices such as phones, embedded computers or microcontrollers.
章概要
- やってみる
- AWS IoT環境準備
- DockerコンテナでMosquitteを立てる
- AWS IoTのMQTTトピック
/demo/event
に対するサブスクリプションを作成する - AWS IoTのMQTTトピック
/demo/event
にPublishする
- 補足
- IoTポリシーとクライアントIDについて
- openSUSEからのmosquitteの取得について
- おわりに
- 参考
やってみる
AWS IoT環境準備
まずはAWS IoTの環境準備を行っていきます。
1. certs
ディレクトリの作成
certs
ディレクトリを作成します。このディレクトリはMosquitteを立てるDockerコンテナからマウントして利用します。
$ mkdir ./certs
2. キーペアとデバイス証明書の作成
AWS CLIで以下のコマンドを実行し、2048ビットのRSAキーペアの作成と、発行された公開鍵を使用してX.509のデバイス証明書の発行を行います。作成した秘密鍵(privateKey.pem
)と証明書(cert.pem
)はcerts
ディレクトリに格納します。
$ aws iot create-keys-and-certificate \ --set-as-active \ --private-key-outfile ./certs/privateKey.pem \ --certificate-pem-outfile ./certs/cert.pem { "certificateArn": "arn:aws:iot:ap-northeast-1:123456789012:cert/00c0479e991dcfa918d67b53762ecd95e1171c7ee984f44399d86a8c581ba817", "certificateId": "00c0479e991dcfa918d67b53762ecd95e1171c7ee984f44399d86a8c581ba817", "certificatePem": "-----BEGIN CERTIFICATE-----\nMIIDWTCCAkGgAwIBAgIULkFh/IUQ6QlCW/2YEIyjihut0FswDQYJKoZIhvcNAQEL\n(中略)-----END CERTIFICATE-----\n", "keyPair": { "PublicKey": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmWgt6TbmhVXxnr9mS+hw\n(中略)-----END PUBLIC KEY-----\n", "PrivateKey": "-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEAmWgt6TbmhVXxnr9mS+hwXVz4//994SNPzY43rLb3us0hEWse\n(中略)-----END RSA PRIVATE KEY-----\n" } }
3. ルートCA証明書の取得
以下のコマンドを実行し、デバイスがAWS IoTをサーバー認証するためのルートCA証明書をAmazonトラストサービスのリポジトリからダウンロードしてcerts
ディレクトリに保存します。
$ curl -o ./certs/rootCA.pem \ -s https://www.amazontrust.com/repository/AmazonRootCA1.pem
4. IoTポリシーの作成
以下のdemo-policy.json
ファイルを作成します。
※後述の手順でMosquitteからPublishする際に、クライアントIDは12行目に記載のdemo-device-id-1
、Publish先のトピックは13行目に記載の/demo/event
を指定します。
$ cat demo-policy.json { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "iot:Connect", "iot:Publish" ], "Resource": [ "arn:aws:iot:ap-northeast-1:123456789012:client/demo-device-id-1", "arn:aws:iot:ap-northeast-1:123456789012:topic//demo/event" ] } ] }
AWS CLIで以下のコマンドを実行し、IoTポリシーdemoPolicy
を作成します。
$ aws iot create-policy \ --policy-name demoPolicy \ --policy-document file://demo-policy.json
5. IoTポリシーをデバイス証明書へアタッチ
AWS CLIで以下のコマンドを実行し、IoTポリシーdemoPolicy
をデバイス証明書にアタッチします。ここで--principal
に指定するのは、iot create-keys-and-certificate
コマンド実行結果のcertificateArn
の値です。
$ aws iot attach-principal-policy \ --policy-name demoPolicy \ --principal arn:aws:iot:ap-northeast-1:123456789012:cert/00c0479e991dcfa918d67b53762ecd95e1171c7ee984f44399d86a8c581ba817
これでAWS IoTの環境準備ができました。(今回はMQTTトピックにpublishをするだけなのでモノの作成は不要です)
DockerコンテナでMosquitteを立てる
mosquitto公式提供のDockerイメージeclipse-mosquitto
からコンテナを起動します。
$ docker run --name mosquitto-demo -v "${PWD}"/certs:/certs -itd eclipse-mosquitto:latest
AWS IoTのMQTTトピック/demo/event
に対するサブスクリプションを作成する
AWS IoTのマネージドコンソールの[テスト]を開きます。[トピックへサブスクライブする]を選択して[トピックのサブスクリプション]にトピック名/demo/event
を入力し、[トピックへのサブスクライブ]をクリックします。
/demo/event
に対するサブスクリプションが作成されます。
AWS IoTのMQTTトピック/demo/event
にPublishする
AWS CLIで以下のコマンドを実行して、Dockerコンテナ上のmosquittoからMQTTトピック/demo/event
に対してメッセージをpublishします。
$ docker exec -it mosquitto-demo /bin/ash -c "mosquitto_pub \ -h $(aws iot describe-endpoint --endpoint-type iot:Data-ATS | jq -r .endpointAddress) \ -p 8883 \ -q 1 \ -i demo-device-id-1 \ -m '{\"message\":\"こんばんは!!!\"}' \ -t /demo/event \ --cafile ./certs/rootCA.pem \ --key ./certs/privateKey.pem \ --cert ./certs/cert.pem"
先程AWSコンソールにて作成したサブスクリプションにて、/demo/event
トピックに対してpublishしたメッセージ{"message": "こんばんは!!!"}
がsubscribeできていることが確認できました。
補足
openSUSEからのmosquitteの取得について
多くの記事では、以下のopenSUSEのURLよりMosquitteクライアントのダウンロードが可能であると紹介されていますが、2020年1月時点では404エラーとなり利用できないようです。
- http://download.opensuse.org/repositories/home:/oojah:/mqtt/CentOS_CentOS-6/home:oojah:mqtt.repo
よって、当たり前ですが、Amazon LinuxやCent OSへ以下のようなコマンドでMosquitteをインストールしようとしても、404エラーのページしかダウンロードできないためyum install
は失敗します。
$ sudo curl http://download.opensuse.org/repositories/home:/oojah:/mqtt/CentOS_CentOS-6/home:oojah:mqtt.repo -o /etc/yum.repos.d/mqtt.repo $ sudo yum install -y mosquitto-clients Loaded plugins: priorities, update-motd, upgrade-helper File contains no section headers. file: file:///etc/yum.repos.d/mqtt.repo, line: 1 '<?xml version="1.0" encoding="UTF-8"?>\n'
そこで私は、Amazon Linux上でMosquitteを利用するために今回紹介したようにDockerでMosquitteを立てる必要があった、という経緯がありました。
IoTポリシーとクライアントIDについて
publish時(mosquitto_pub
コマンド実行時)に-i
オプションで指定するクライアントIDと、同リクエスト時に送信されるデバイス証明書にアタッチされるIoTポリシーで許可されるクライアントIDリソースがどのような組み合わせパターンのときにどのような動作となるか整理しました。
パターン1
- mosquitto_pubコマンドでの指定:
demo-device-id-1
- IoTポリシーでの許可:
demo-device-id-1
本記事[やってみた]にてご紹介したパターンです。トピックへのpublish時に指定したクライアントID(demo-device-id-1
)がIoTポリシーで許可されているため、publish可能となります。
- IoTポリシー
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "iot:Connect", "iot:Publish" ], "Resource": [ "arn:aws:iot:ap-northeast-1:123456789012:client/demo-device-id-1", "arn:aws:iot:ap-northeast-1:123456789012:topic//demo/event" ] } ] }
mosquitto_pub
コマンドの実行
$ docker exec -it mqtt /bin/ash -c "mosquitto_pub \ -h $(aws iot describe-endpoint --endpoint-type iot:Data-ATS | jq -r .endpointAddress) \ -p 8883 \ -q 1 \ -i demo-device-id-1 \ -m '{\"message\":\"こんばんは\"}' \ -t /demo/event \ --cafile ./certs/rootCA.pem \ --key ./certs/privateKey.pem \ --cert ./certs/cert.pem"
パターン2
- mosquitto_pubコマンドでの指定:
demo-device-id-any
- IoTポリシーでの許可:
demo-device-id-1
トピックへのpublish時に指定したクライアントID(demo-device-id-any
)がIoTポリシーで許可されていないため、publish不可となります。
- IoTポリシー
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "iot:Connect", "iot:Publish" ], "Resource": [ "arn:aws:iot:ap-northeast-1:123456789012:client/demo-device-id-1", "arn:aws:iot:ap-northeast-1:123456789012:topic//demo/event" ] } ] }
mosquitto_pub
コマンドの実行
$ docker exec -it mqtt /bin/ash -c "mosquitto_pub \ -h $(aws iot describe-endpoint --endpoint-type iot:Data-ATS | jq -r .endpointAddress) \ -p 8883 \ -q 1 \ -i demo-device-id-any \ -m '{\"message\":\"こんばんは\"}' \ -t /demo/event \ --cafile ./certs/rootCA.pem \ --key ./certs/privateKey.pem \ --cert ./certs/cert.pem" Error: The connection was lost.
パターン3
- mosquitto_pubコマンドでの指定:
demo-device-id-any
- IoTポリシーでの許可:
*
IoTポリシーでワイルドカード*
により任意のクライアントIDが許可されているため、任意のクライアントID(demo-device-id-any
など)を指定してpublish可能となります。
- IoTポリシー
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "iot:Connect", "iot:Publish" ], "Resource": [ "arn:aws:iot:ap-northeast-1:123456789012:client/*", "arn:aws:iot:ap-northeast-1:123456789012:topic//demo/event" ] } ] }
mosquitto_pub
コマンドの実行
$ docker exec -it mqtt /bin/ash -c "mosquitto_pub \ -h $(aws iot describe-endpoint --endpoint-type iot:Data-ATS | jq -r .endpointAddress) \ -p 8883 \ -q 1 \ -i demo-device-id-any \ -m '{\"message\":\"こんばんは\"}' \ -t /demo/event \ --cafile ./certs/rootCA.pem \ --key ./certs/privateKey.pem \ --cert ./certs/cert.pem"
おわりに
AWS IoT上のMQTTトピックに対してDockerコンテナ上のMosquitteからメッセージをpublishしてみました。AWS IoT側の環境準備さえできていれば「コンテナ起動→コンテナ上でmosquitto_pubコマンド実行」の2ステップでMQTTトピックにpublishが行えるため、ちょっとしたトピック発行の検証をしたい時に重宝しそうです。参考になれば幸いです。